#include <iostream>
#include <string>
#include <memory>
#include "Reactor.hpp"  //负责事件就绪派发
#include "Listener.hpp" //负责连接获取
#include "Channel.hpp"  //负责IO处理
#include "Log.hpp"
#include "Common.hpp"
#include "Protocol.hpp" //负责协议
#include "NetCal.hpp"   //负责业务处理

static void Usage(std::string proc)
{
  std::cerr << "Usage: " << proc << " port" << std::endl;
}

int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    Usage(argv[0]);
    exit(USAGE_ERR);
  }
  uint16_t port = std::stoi(argv[1]);

  LogModule::ConsoleLogStrategy();

  // 1.构建业务处理对象，将来要设置进协议对象中
  std::shared_ptr<Cal> cal = std::make_shared<Cal>();

  // 2.构建协议对象，将来要设置到Listener对象中
  std::shared_ptr<Protocol> protocol = std::make_shared<Protocol>([&cal](Request &req) -> Response
                                                                  { return cal->Execute(req); });

  // 3.构建一个Listener对象，会间接和Channel模块一起设置到Reactor对象
  std::shared_ptr<Connection> conn = std::make_shared<Listener>(port);
  // 注册一下协议方法来处理Channel对象
  conn->RegisterHandler([&protocol](std::string &inbuffer) -> std::string
                        {
                              LOG(LogLevel::DEBUG)<<"进入到匿名函数中...";
                              // 这个匿名函数就是要被Channel执行的
                              std::string response_str;
                              //循环处理多个报文
                              while(true)
                              {
                                std::string package;
                                if (!protocol->Decode(inbuffer, &package))
                                  // 没有完整报文了，退出循环
                                  break;

                                // 能确保我们的package一定是一个完整的请求，是字节流的
                                //直接调用protocol的Execute方法转换成字节流风格的response
                                response_str += protocol->Execute(package); 
                              }
                              return response_str; });

  // 4. 构建一个反应堆，Reactor模块
  std::unique_ptr<Reactor> R = std::make_unique<Reactor>();

  // 先把我们的listensocket模块新增进Reactor中
  // listen套接字模块在我们看来就是一个Connection
  // Reactor反应堆其实就是一个把所有连接管理起来的一个容器
  R->AddConnection(conn);

  // 紧接着让服务器启动起来
  R->Loop();

  return 0;
}